package com.linsen.core.jetcache.config;

import cn.hutool.core.util.StrUtil;
import com.alicp.jetcache.CacheBuilder;
import com.alicp.jetcache.anno.CacheConsts;
import com.alicp.jetcache.anno.config.EnableCreateCacheAnnotation;
import com.alicp.jetcache.anno.config.EnableMethodCache;
import com.alicp.jetcache.anno.support.GlobalCacheConfig;
import com.alicp.jetcache.anno.support.SpringConfigProvider;
import com.alicp.jetcache.embedded.EmbeddedCacheBuilder;
import com.alicp.jetcache.embedded.LinkedHashMapCacheBuilder;
import com.alicp.jetcache.redis.springdata.RedisSpringDataCacheBuilder;
import com.alicp.jetcache.support.FastjsonKeyConvertor;
import com.alicp.jetcache.support.JavaValueDecoder;
import com.alicp.jetcache.support.JavaValueEncoder;
import com.linsen.core.common.annotation.AutoConfiguration;
import com.linsen.core.common.factory.YamlPropertySourceFactory;
import com.linsen.core.jetcache.props.LinsenJetCacheProperties;
import io.lettuce.core.ClientOptions;
import io.lettuce.core.RedisClient;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;

import java.util.HashMap;
import java.util.Map;

/**
 * @author zhaoyong
 * @date 2023/3/11
 * <a href="https://www.jianshu.com/p/f2939ca68df5">...</a>
 */
@AutoConfiguration
@EnableMethodCache(basePackages = "com.linsen")
@EnableCreateCacheAnnotation
@RequiredArgsConstructor
@EnableConfigurationProperties({LinsenJetCacheProperties.class})
@PropertySource(factory = YamlPropertySourceFactory.class, value = "classpath:linsen-jetcache.yml")
public class LinsenJetCacheAutoConfiguration {
    private final LinsenJetCacheProperties jetCacheProperties;

    @Bean
    public RedisClient redisClient() {
        // redis://:password@host:port/database
        RedisClient client = RedisClient.create(StrUtil.format("redis://:{}@{}:{}/{}", this.jetCacheProperties.getRedisPassword(), this.jetCacheProperties.getRedisHost(), this.jetCacheProperties.getRedisPort(), this.jetCacheProperties.getRedisDatabase()));
        client.setOptions(ClientOptions.builder().
                disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)
                .build());
        return client;
    }

    @Bean
    public SpringConfigProvider springConfigProvider() {
        return new SpringConfigProvider();
    }

    @Bean
    public GlobalCacheConfig config(SpringConfigProvider configProvider, RedisClient redisClient) {
        Map<String, CacheBuilder> localBuilders = new HashMap<>();
        EmbeddedCacheBuilder<?> localBuilder = LinkedHashMapCacheBuilder
                .createLinkedHashMapCacheBuilder()
                .keyConvertor(FastjsonKeyConvertor.INSTANCE);
        localBuilders.put(CacheConsts.DEFAULT_AREA, localBuilder);

        Map<String, CacheBuilder> remoteBuilders = new HashMap<>(6);
        RedisSpringDataCacheBuilder<?> redisSpringDataCacheBuilder = RedisSpringDataCacheBuilder.createBuilder()
                .keyConvertor(FastjsonKeyConvertor.INSTANCE)
                .valueEncoder(JavaValueEncoder.INSTANCE)
                .valueDecoder(JavaValueDecoder.INSTANCE);
        remoteBuilders.put(CacheConsts.DEFAULT_AREA, redisSpringDataCacheBuilder);

        GlobalCacheConfig globalCacheConfig = new GlobalCacheConfig();
        // globalCacheConfig.setConfigProvider(configProvider);//for jetcache <=2.5
        globalCacheConfig.setLocalCacheBuilders(localBuilders);
        globalCacheConfig.setRemoteCacheBuilders(remoteBuilders);
        globalCacheConfig.setStatIntervalMinutes(15);
        globalCacheConfig.setAreaInCacheName(false);

        return globalCacheConfig;
    }
}
